home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / GIFLIB12.ARJ / EGIF_LIB.C < prev    next >
C/C++ Source or Header  |  1991-08-05  |  27KB  |  775 lines

  1. /******************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                      *
  3. *                                          *
  4. * Written by:  Gershon Elber                Ver 1.1, Aug. 1990    *
  5. *******************************************************************************
  6. * The kernel of the GIF Encoding process can be found here.              *
  7. *******************************************************************************
  8. * History:                                      *
  9. * 14 Jun 89 - Version 1.0 by Gershon Elber.                      *
  10. *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
  11. ******************************************************************************/
  12.  
  13. #ifdef __MSDOS__
  14. #include <io.h>
  15. #include <alloc.h>
  16. #include <sys\stat.h>
  17. #else
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #ifdef R6000
  21. #include <sys/mode.h>
  22. #endif
  23. #endif /* __MSDOS__ */
  24.  
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include "gif_lib.h"
  29. #include "gif_hash.h"
  30.  
  31. #define PROGRAM_NAME    "GIF_LIBRARY"
  32.  
  33. #define COMMENT_EXT_FUNC_CODE    0xfe /* Extension function code for comment. */
  34. #define GIF_STAMP    "GIF87a"         /* First chars in file - GIF stamp. */
  35. #define ZL_MAX_CODE    4095        /* Biggest code possible in 12 bits. */
  36.  
  37. #define FILE_STATE_WRITE    0x01/* 1 write, 0 read - DGIF_LIB compatible.*/
  38. #define FILE_STATE_SCREEN    0x02
  39. #define FILE_STATE_IMAGE    0x04
  40.  
  41. #define FLUSH_OUTPUT        4096    /* Impossible code, to signal flush. */
  42. #define FIRST_CODE        4097    /* Impossible code, to signal first. */
  43.  
  44. #define IS_WRITEABLE(Private)    (Private -> FileState & FILE_STATE_WRITE)
  45.  
  46. /* #define DEBUG_NO_PREFIX                  Dump only compressed data. */
  47.  
  48. typedef struct GifFilePrivateType {
  49.     int FileState,
  50.     FileHandle,                 /* Where old this data goes to! */
  51.     BitsPerPixel,        /* Bits per pixel (Codes uses at list this + 1). */
  52.     ClearCode,                       /* The CLEAR LZ code. */
  53.     EOFCode,                     /* The EOF LZ code. */
  54.     RunningCode,            /* The next code algorithm can generate. */
  55.     RunningBits,/* The number of bits required to represent RunningCode. */
  56.     MaxCode1,  /* 1 bigger than max. possible code, in RunningBits bits. */
  57.     CrntCode,                  /* Current algorithm code. */
  58.     CrntShiftState;            /* Number of bits in CrntShiftDWord. */
  59.     unsigned long CrntShiftDWord,     /* For bytes decomposition into codes. */
  60.           PixelCount;
  61.     FILE *File;                          /* File as stream. */
  62.     GifByteType Buf[256];          /* Compressed output is buffered here. */
  63.     GifHashTableType *HashTable;
  64. } GifFilePrivateType;
  65.  
  66. extern int _GifError;
  67.  
  68. /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
  69. static GifPixelType CodeMask[] = {
  70.     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
  71. };
  72.  
  73. #ifdef SYSV
  74. static char *VersionStr =
  75.         "Gif library module,\t\tGershon Elber\n\
  76.     (C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  77. #else
  78. static char *VersionStr =
  79.     PROGRAM_NAME
  80.     "    IBMPC "
  81.     GIF_LIB_VERSION
  82.     "    Gershon Elber,    "
  83.     __DATE__ ",   " __TIME__ "\n"
  84.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  85. #endif /* SYSV */
  86.  
  87. static char *GifVersionPrefix = GIF_STAMP;
  88.  
  89. static int EGifPutWord(int Word, FILE *File);
  90. static int EGifSetupCompress(GifFileType *GifFile);
  91. static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
  92.                                 int LineLen);
  93. static int EGifCompressOutput(GifFilePrivateType *Private, int Code);
  94. static int EGifBufferedOutput(FILE *File, GifByteType *Buf, int c);
  95.  
  96. /******************************************************************************
  97. *   Open a new gif file for write, given by its name. If TestExistance then   *
  98. * if the file exists this routines fails (returns NULL).              *
  99. *   Returns GifFileType pointer dynamically allocated which serves as the gif *
  100. * info record. _GifError is cleared if succesfull.                  *
  101. ******************************************************************************/
  102. GifFileType *EGifOpenFileName(char *FileName, int TestExistance)
  103. {
  104.     int FileHandle;
  105.  
  106.     if (TestExistance)
  107.     FileHandle = open(FileName,
  108.               O_WRONLY | O_CREAT | O_EXCL
  109. #ifdef __MSDOS__
  110.                                  | O_BINARY
  111. #endif /* __MSDOS__ */
  112.                                            ,
  113.               S_IREAD | S_IWRITE);
  114.     else
  115.     FileHandle = open(FileName,
  116.               O_WRONLY | O_CREAT | O_TRUNC
  117. #ifdef __MSDOS__
  118.                                  | O_BINARY
  119. #endif /* __MSDOS__ */
  120.                                            ,
  121.               S_IREAD | S_IWRITE);
  122.  
  123.     if (FileHandle == -1) {
  124.     _GifError = E_GIF_ERR_OPEN_FAILED;
  125.     return NULL;
  126.     }
  127.  
  128.     return EGifOpenFileHandle(FileHandle);
  129. }
  130.  
  131. /******************************************************************************
  132. *   Update a new gif file, given its file handle, which must be opened for    *
  133. * write in binary mode.                                  *
  134. *   Returns GifFileType pointer dynamically allocated which serves as the gif *
  135. * info record. _GifError is cleared if succesfull.                  *
  136. ******************************************************************************/
  137. GifFileType *EGifOpenFileHandle(int FileHandle)
  138. {
  139.     GifFileType *GifFile;
  140.     GifFilePrivateType *Private;
  141.     FILE *f;
  142.  
  143. #ifdef __MSDOS__
  144.     setmode(FileHandle, O_BINARY);      /* Make sure it is in binary mode. */
  145.     f = fdopen(FileHandle, "wb");           /* Make it into a stream: */
  146.     setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);   /* And inc. stream buffer. */
  147. #else
  148.     f = fdopen(FileHandle, "w");           /* Make it into a stream: */
  149. #endif /* __MSDOS__ */
  150.  
  151.     if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
  152.     _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
  153.     return NULL;
  154.     }
  155.  
  156.     GifFile -> SWidth = GifFile -> SHeight =
  157.     GifFile -> SColorResolution = GifFile -> SBitsPerPixel =
  158.     GifFile -> SBackGroundColor =
  159.     GifFile -> ILeft = GifFile -> ITop = GifFile -> IWidth = GifFile -> IHeight =
  160.     GifFile -> IInterlace =
  161.     GifFile -> IBitsPerPixel = 0;
  162.  
  163.     GifFile -> SColorMap = GifFile -> IColorMap = NULL;
  164.  
  165. #ifndef DEBUG_NO_PREFIX
  166.     if (fwrite(GifVersionPrefix, 1, strlen(GifVersionPrefix), f) !=
  167.                         strlen(GifVersionPrefix)) {
  168.     _GifError = E_GIF_ERR_WRITE_FAILED;
  169.     free((char *) GifFile);
  170.     return NULL;
  171.     }
  172. #endif /* DEBUG_NO_PREFIX */
  173.  
  174.     if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
  175.     == NULL) {
  176.     _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
  177.     return NULL;
  178.     }
  179.  
  180.     GifFile -> Private = (VoidPtr) Private;
  181.     Private -> FileHandle = FileHandle;
  182.     Private -> File = f;
  183.     Private -> FileState = FILE_STATE_WRITE;
  184.     if ((Private -> HashTable = _InitHashTable()) == NULL) {
  185.     _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
  186.     return NULL;
  187.     }
  188.  
  189.     _GifError = 0;
  190.  
  191.     return GifFile;
  192. }
  193.  
  194. /******************************************************************************
  195. *   Routine to set current GIF version. All files open for write will be      *
  196. * using this version until next call to this routine. Version consists of     *
  197. * 3 characters as "87a" or "89a". No test is made to validate the version.    *
  198. ******************************************************************************/
  199. void EGifSetGifVersion(char *Version)
  200. {
  201.     strncpy(&GifVersionPrefix[3], Version, 3);
  202. }
  203.  
  204. /******************************************************************************
  205. *   This routine should be called before any other EGif calls, immediately    *
  206. * follows the GIF file openning.                          *
  207. ******************************************************************************/
  208. int EGifPutScreenDesc(GifFileType *GifFile,
  209.     int Width, int Height, int ColorRes, int BackGround,
  210.     int BitsPerPixel, GifColorType *ColorMap)
  211. {
  212.     int i, Size;
  213.     GifByteType Buf[3];
  214.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  215.  
  216.     if (Private -> FileState & FILE_STATE_SCREEN) {
  217.     /* If already has screen descriptor - something is wrong! */
  218.     _GifError = E_GIF_ERR_HAS_SCRN_DSCR;
  219.     return GIF_ERROR;
  220.     }
  221.     if (!IS_WRITEABLE(Private)) {
  222.     /* This file was NOT open for writing: */
  223.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  224.     return GIF_ERROR;
  225.     }
  226.  
  227.     GifFile -> SWidth = Width;
  228.     GifFile -> SHeight = Height;
  229.     GifFile -> SColorResolution = ColorRes;
  230.     GifFile -> SBitsPerPixel = BitsPerPixel;
  231.     GifFile -> SBackGroundColor = BackGround;
  232.     if (ColorMap) {
  233.     Size = sizeof(GifColorType) * (1 << BitsPerPixel);
  234.     GifFile -> SColorMap = (GifColorType *) malloc(Size);
  235.     memcpy(GifFile -> SColorMap, ColorMap, Size);
  236.     }
  237.  
  238.     /* Put the screen descriptor into the file: */
  239.     EGifPutWord(Width, Private -> File);
  240.     EGifPutWord(Height, Private -> File);
  241.     Buf[0] = (ColorMap ? 0x80 : 0x00) |
  242.          ((ColorRes - 1) << 4) |
  243.          (BitsPerPixel - 1);
  244.     Buf[1] = BackGround;
  245.     Buf[2] = 0;
  246. #ifndef DEBUG_NO_PREFIX
  247.     fwrite(Buf, 1, 3, Private -> File);
  248. #endif /* DEBUG_NO_PREFIX */
  249.  
  250.     /* If we have Global color map - dump it also: */
  251. #ifndef DEBUG_NO_PREFIX
  252.     if (ColorMap != NULL)
  253.     for (i = 0; i < (1 << BitsPerPixel); i++) {
  254.         /* Put the ColorMap out also: */
  255.         Buf[0] = ColorMap[i].Red;
  256.         Buf[1] = ColorMap[i].Green;
  257.         Buf[2] = ColorMap[i].Blue;
  258.         if (fwrite(Buf, 1, 3, Private -> File) != 3) {
  259.             _GifError = E_GIF_ERR_WRITE_FAILED;
  260.         return GIF_ERROR;
  261.         }
  262.     }
  263. #endif /* DEBUG_NO_PREFIX */
  264.  
  265.     /* Mark this file as has screen descriptor, and no pixel written yet: */
  266.     Private -> FileState |= FILE_STATE_SCREEN;
  267.  
  268.     return GIF_OK;
  269. }
  270.  
  271. /******************************************************************************
  272. *   This routine should be called before any attemp to dump an image - any    *
  273. * call to any of the pixel dump routines.                      *
  274. ******************************************************************************/
  275. int EGifPutImageDesc(GifFileType *GifFile,
  276.     int Left, int Top, int Width, int Height, int Interlace,
  277.     int BitsPerPixel, GifColorType *ColorMap)
  278. {
  279.     int i, Size;
  280.     GifByteType Buf[3];
  281.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  282.  
  283.     if (Private -> FileState & FILE_STATE_IMAGE &&
  284. #ifdef __MSDOS__
  285.     Private -> PixelCount > 0xffff0000UL) {
  286. #else
  287.     Private -> PixelCount > 0xffff0000) {
  288. #endif /* __MSDOS__ */
  289.     /* If already has active image descriptor - something is wrong! */
  290.     _GifError = E_GIF_ERR_HAS_IMAG_DSCR;
  291.     return GIF_ERROR;
  292.     }
  293.     if (!IS_WRITEABLE(Private)) {
  294.     /* This file was NOT open for writing: */
  295.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  296.     return GIF_ERROR;
  297.     }
  298.     GifFile -> ILeft = Left;
  299.     GifFile -> ITop = Top;
  300.     GifFile -> IWidth = Width;
  301.     GifFile -> IHeight = Height;
  302.     GifFile -> IBitsPerPixel = BitsPerPixel;
  303.     GifFile -> IInterlace = Interlace;
  304.     if (ColorMap) {
  305.     Size = sizeof(GifColorType) * (1 << BitsPerPixel);
  306.     if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
  307.     GifFile -> IColorMap = (GifColorType *) malloc(Size);
  308.     memcpy(GifFile -> IColorMap, ColorMap, Size);
  309.     }
  310.  
  311.     /* Put the image descriptor into the file: */
  312.     Buf[0] = ',';                   /* Image seperator character. */
  313. #ifndef DEBUG_NO_PREFIX
  314.     fwrite(Buf, 1, 1, Private -> File);
  315. #endif /* DEBUG_NO_PREFIX */
  316.     EGifPutWord(Left, Private -> File);
  317.     EGifPutWord(Top, Private -> File);
  318.     EGifPutWord(Width, Private -> File);
  319.     EGifPutWord(Height, Private -> File);
  320.     Buf[0] = (ColorMap ? 0x80 : 0x00) |
  321.       (Interlace ? 0x40 : 0x00) |
  322.       (BitsPerPixel - 1);
  323. #ifndef DEBUG_NO_PREFIX
  324.     fwrite(Buf, 1, 1, Private -> File);
  325. #endif /* DEBUG_NO_PREFIX */
  326.  
  327.     /* If we have Global color map - dump it also: */
  328. #ifndef DEBUG_NO_PREFIX
  329.     if (ColorMap != NULL)
  330.     for (i = 0; i < (1 << BitsPerPixel); i++) {
  331.         /* Put the ColorMap out also: */
  332.         Buf[0] = ColorMap[i].Red;
  333.         Buf[1] = ColorMap[i].Green;
  334.         Buf[2] = ColorMap[i].Blue;
  335.         if (fwrite(Buf, 1, 3, Private -> File) != 3) {
  336.             _GifError = E_GIF_ERR_WRITE_FAILED;
  337.         return GIF_ERROR;
  338.         }
  339.     }
  340. #endif /* DEBUG_NO_PREFIX */
  341.     if (GifFile -> SColorMap == NULL && GifFile -> IColorMap == NULL)
  342.     {
  343.     _GifError = E_GIF_ERR_NO_COLOR_MAP;
  344.     return GIF_ERROR;
  345.     }
  346.  
  347.     /* Mark this file as has screen descriptor: */
  348.     Private -> FileState |= FILE_STATE_IMAGE;
  349.     Private -> PixelCount = (long) Width * (long) Height;
  350.  
  351.     EGifSetupCompress(GifFile);      /* Reset compress algorithm parameters. */
  352.  
  353.     return GIF_OK;
  354. }
  355.  
  356. /******************************************************************************
  357. *  Put one full scanned line (Line) of length LineLen into GIF file.          *
  358. ******************************************************************************/
  359. int EGifPutLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
  360. {
  361.     int i;
  362.     GifPixelType Mask;
  363.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  364.  
  365.     if (!IS_WRITEABLE(Private)) {
  366.     /* This file was NOT open for writing: */
  367.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  368.     return GIF_ERROR;
  369.     }
  370.  
  371.     if (!LineLen) LineLen = GifFile -> IWidth;
  372.     if ((Private -> PixelCount -= LineLen) < 0) {
  373.     _GifError = E_GIF_ERR_DATA_TOO_BIG;
  374.     return GIF_ERROR;
  375.     }
  376.  
  377.     /* Make sure the codes are not out of bit range, as we might generate    */
  378.     /* wrong code (because of overflow when we combine them) in this case:   */
  379.     Mask = CodeMask[Private -> BitsPerPixel];
  380.     for (i = 0; i < LineLen; i++) Line[i] &= Mask;
  381.  
  382.     return EGifCompressLine(GifFile, Line, LineLen);
  383. }
  384.  
  385. /******************************************************************************
  386. * Put one pixel (Pixel) into GIF file.                          *
  387. ******************************************************************************/
  388. int EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel)
  389. {
  390.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  391.  
  392.     if (!IS_WRITEABLE(Private)) {
  393.     /* This file was NOT open for writing: */
  394.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  395.     return GIF_ERROR;
  396.     }
  397.  
  398.     if (--Private -> PixelCount < 0)
  399.     {
  400.     _GifError = E_GIF_ERR_DATA_TOO_BIG;
  401.     return GIF_ERROR;
  402.     }
  403.  
  404.     /* Make sure the code is not out of bit range, as we might generate         */
  405.     /* wrong code (because of overflow when we combine them) in this case:   */
  406.     Pixel &= CodeMask[Private -> BitsPerPixel];
  407.  
  408.     return EGifCompressLine(GifFile, &Pixel, 1);
  409. }
  410.  
  411. /******************************************************************************
  412. * Put a comment into GIF file using extension block.                  *
  413. ******************************************************************************/
  414. int EGifPutComment(GifFileType *GifFile, char *Comment)
  415. {
  416.     return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE, strlen(Comment),
  417.                                 Comment);
  418. }
  419.  
  420. /******************************************************************************
  421. *   Put an extension block (see GIF manual) into gif file.              *
  422. ******************************************************************************/
  423. int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen,
  424.                             VoidPtr Extension)
  425. {
  426.     GifByteType Buf[3];
  427.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  428.  
  429.     if (!IS_WRITEABLE(Private)) {
  430.     /* This file was NOT open for writing: */
  431.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  432.     return GIF_ERROR;
  433.     }
  434.  
  435.     Buf[0] = '!';
  436.     Buf[1] = ExtCode;
  437.     Buf[2] = ExtLen;
  438.     fwrite(Buf, 1, 3, Private -> File);
  439.     fwrite(Extension, 1, ExtLen, Private -> File);
  440.     Buf[0] = 0;
  441.     fwrite(Buf, 1, 1, Private -> File);
  442.  
  443.     return GIF_OK;
  444. }
  445.  
  446. /******************************************************************************
  447. *   Put the image code in compressed form. This routine can be called if the  *
  448. * information needed to be piped out as is. Obviously this is much faster     *
  449. * than decoding and encoding again. This routine should be followed by calls  *
  450. * to EGifPutCodeNext, until NULL block is given.                  *
  451. *   The block should NOT be freed by the user (not dynamically allocated).    *
  452. ******************************************************************************/
  453. int EGifPutCode(GifFileType *GifFile, int CodeSize, GifByteType *CodeBlock)
  454. {
  455.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  456.  
  457.     if (!IS_WRITEABLE(Private)) {
  458.     /* This file was NOT open for writing: */
  459.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  460.     return GIF_ERROR;
  461.     }
  462.  
  463.     /* No need to dump code size as Compression set up does any for us: */
  464.     /*
  465.     Buf = CodeSize;
  466.     if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
  467.     _GifError = E_GIF_ERR_WRITE_FAILED;
  468.     return GIF_ERROR;
  469.     }
  470.     */
  471.  
  472.     return EGifPutCodeNext(GifFile, CodeBlock);
  473. }
  474.  
  475. /******************************************************************************
  476. *   Continue to put the image code in compressed form. This routine should be *
  477. * called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If      *
  478. * given buffer pointer is NULL, empty block is written to mark end of code.   *
  479. ******************************************************************************/
  480. int EGifPutCodeNext(GifFileType *GifFile, GifByteType *CodeBlock)
  481. {
  482.     GifByteType Buf;
  483.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  484.  
  485.     if (CodeBlock != NULL) {
  486.     if (fwrite(CodeBlock, 1, CodeBlock[0] + 1, Private -> File)
  487.                             != CodeBlock[0] + 1) {
  488.         _GifError = E_GIF_ERR_WRITE_FAILED;
  489.         return GIF_ERROR;
  490.     }
  491.     }
  492.     else {
  493.     Buf = 0;
  494.     if (fwrite(&Buf, 1, 1, Private -> File) != 1) {
  495.         _GifError = E_GIF_ERR_WRITE_FAILED;
  496.         return GIF_ERROR;
  497.     }
  498.     Private -> PixelCount = 0;   /* And local info. indicate image read. */
  499.     }
  500.  
  501.     return GIF_OK;
  502. }
  503.  
  504. /******************************************************************************
  505. *   This routine should be called last, to close GIF file.              *
  506. ******************************************************************************/
  507. int EGifCloseFile(GifFileType *GifFile)
  508. {
  509.     GifByteType Buf;
  510.     GifFilePrivateType *Private;
  511.     FILE *File;
  512.  
  513.     if (GifFile == NULL) return GIF_ERROR;
  514.  
  515.     Private = (GifFilePrivateType *) GifFile -> Private;
  516.     if (!IS_WRITEABLE(Private)) {
  517.     /* This file was NOT open for writing: */
  518.     _GifError = E_GIF_ERR_NOT_WRITEABLE;
  519.     return GIF_ERROR;
  520.     }
  521.  
  522.     File = Private -> File;
  523.  
  524.     Buf = ';';
  525.     fwrite(&Buf, 1, 1, Private -> File);
  526.  
  527.     if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap);
  528.     if (GifFile -> SColorMap) free((char *) GifFile -> SColorMap);
  529.     if (Private) {
  530.     if (Private -> HashTable) free((char *) Private -> HashTable);
  531.     free((char *) Private);
  532.     }
  533.     free(GifFile);
  534.  
  535.     if (fclose(File) != 0) {
  536.     _GifError = E_GIF_ERR_CLOSE_FAILED;
  537.     return GIF_ERROR;
  538.     }
  539.     return GIF_OK;
  540. }
  541.  
  542. /******************************************************************************
  543. *   Put 2 bytes (word) into the given file:                      *
  544. ******************************************************************************/
  545. static int EGifPutWord(int Word, FILE *File)
  546. {
  547.     char c[2];
  548.  
  549.     c[0] = Word & 0xff;
  550.     c[1] = (Word >> 8) & 0xff;
  551. #ifndef DEBUG_NO_PREFIX
  552.     if (fwrite(c, 1, 2, File) == 2)
  553.     return GIF_OK;
  554.     else
  555.     return GIF_ERROR;
  556. #else
  557.     return GIF_OK;
  558. #endif /* DEBUG_NO_PREFIX */
  559. }
  560.  
  561. /******************************************************************************
  562. *   Setup the LZ compression for this image:                      *
  563. ******************************************************************************/
  564. static int EGifSetupCompress(GifFileType *GifFile)
  565. {
  566.     int BitsPerPixel;
  567.     GifByteType Buf;
  568.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  569.  
  570.     /* Test and see what color map to use, and from it # bits per pixel: */
  571.     if (GifFile -> IColorMap)
  572.     BitsPerPixel = GifFile -> IBitsPerPixel;
  573.     else if (GifFile -> SColorMap)
  574.     BitsPerPixel = GifFile -> SBitsPerPixel;
  575.     else {
  576.     _GifError = E_GIF_ERR_NO_COLOR_MAP;
  577.     return GIF_ERROR;
  578.     }
  579.  
  580.     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
  581.     fwrite(&Buf, 1, 1, Private -> File);     /* Write the Code size to file. */
  582.  
  583.     Private -> Buf[0] = 0;              /* Nothing was output yet. */
  584.     Private -> BitsPerPixel = BitsPerPixel;
  585.     Private -> ClearCode = (1 << BitsPerPixel);
  586.     Private -> EOFCode = Private -> ClearCode + 1;
  587.     Private -> RunningCode = Private -> EOFCode + 1;
  588.     Private -> RunningBits = BitsPerPixel + 1;     /* Number of bits per code. */
  589.     Private -> MaxCode1 = 1 << Private -> RunningBits;       /* Max. code + 1. */
  590.     Private -> CrntCode = FIRST_CODE;       /* Signal that this is first one! */
  591.     Private -> CrntShiftState = 0;      /* No information in CrntShiftDWord. */
  592.     Private -> CrntShiftDWord = 0;
  593.  
  594.     /* Clear hash table and send Clear to make sure the decoder do the same. */
  595.     _ClearHashTable(Private -> HashTable);
  596.     if (EGifCompressOutput(Private, Private -> ClearCode) == GIF_ERROR) {
  597.     _GifError = E_GIF_ERR_DISK_IS_FULL;
  598.     return GIF_ERROR;
  599.     }
  600.     return GIF_OK;
  601. }
  602.  
  603. /******************************************************************************
  604. *   The LZ compression routine:                              *
  605. *   This version compress the given buffer Line of length LineLen.          *
  606. *   This routine can be called few times (one per scan line, for example), in *
  607. * order the complete the whole image.                          *
  608. ******************************************************************************/
  609. static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
  610.                                 int LineLen)
  611. {
  612.     int i = 0, CrntCode, NewCode;
  613.     unsigned long NewKey;
  614.     GifPixelType Pixel;
  615.     GifHashTableType *HashTable;
  616.     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private;
  617.  
  618.     HashTable = Private -> HashTable;
  619.  
  620.     if (Private -> CrntCode == FIRST_CODE)          /* Its first time! */
  621.     CrntCode = Line[i++];
  622.     else
  623.         CrntCode = Private -> CrntCode;     /* Get last code in compression. */
  624.  
  625.     while (i < LineLen) {                /* Decode LineLen items. */
  626.     Pixel = Line[i++];              /* Get next pixel from stream. */
  627.     /* Form a new unique key to search hash table for the code combines  */
  628.     /* CrntCode as Prefix string with Pixel as postfix char.         */
  629.     NewKey = (((unsigned long) CrntCode) << 8) + Pixel;
  630.     if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
  631.         /* This Key is already there, or the string is old one, so         */
  632.         /* simple take new code as our CrntCode:                 */
  633.         CrntCode = NewCode;
  634.     }
  635.     else {
  636.         /* Put it in hash table, output the prefix code, and make our    */
  637.         /* CrntCode equal to Pixel.                         */
  638.         if (EGifCompressOutput(Private, CrntCode)
  639.         == GIF_ERROR) {
  640.         _GifError = E_GIF_ERR_DISK_IS_FULL;
  641.         return GIF_ERROR;
  642.         }
  643.         CrntCode = Pixel;
  644.  
  645.         /* If however the HashTable if full, we send a clear first and   */
  646.         /* Clear the hash table.                         */
  647.         if (Private -> RunningCode >= ZL_MAX_CODE) {
  648.         /* Time to do some clearance: */
  649.         if (EGifCompressOutput(Private, Private -> ClearCode)
  650.             == GIF_ERROR) {
  651.             _GifError = E_GIF_ERR_DISK_IS_FULL;
  652.             return GIF_ERROR;
  653.         }
  654.         Private -> RunningCode = Private -> EOFCode + 1;
  655.         Private -> RunningBits = Private -> BitsPerPixel + 1;
  656.         Private -> MaxCode1 = 1 << Private -> RunningBits;
  657.         _ClearHashTable(HashTable);
  658.         }
  659.         else {
  660.         /* Put this unique key with its relative Code in hash table: */
  661.         _InsertHashTable(HashTable, NewKey, Private -> RunningCode++);
  662.         }
  663.     }
  664.     }
  665.  
  666.     /* Preserve the current state of the compression algorithm: */
  667.     Private -> CrntCode = CrntCode;
  668.  
  669.     if (Private -> PixelCount == 0)
  670.     {
  671.     /* We are done - output last Code and flush output buffers: */
  672.     if (EGifCompressOutput(Private, CrntCode)
  673.         == GIF_ERROR) {
  674.         _GifError = E_GIF_ERR_DISK_IS_FULL;
  675.         return GIF_ERROR;
  676.     }
  677.     if (EGifCompressOutput(Private, Private -> EOFCode)
  678.         == GIF_ERROR) {
  679.         _GifError = E_GIF_ERR_DISK_IS_FULL;
  680.         return GIF_ERROR;
  681.     }
  682.     if (EGifCompressOutput(Private, FLUSH_OUTPUT) == GIF_ERROR) {
  683.         _GifError = E_GIF_ERR_DISK_IS_FULL;
  684.         return GIF_ERROR;
  685.     }
  686.     }
  687.  
  688.     return GIF_OK;
  689. }
  690.  
  691. /******************************************************************************
  692. *   The LZ compression output routine:                          *
  693. *   This routine is responsable for the compression of the bit stream into    *
  694. * 8 bits (bytes) packets.                              *
  695. *   Returns GIF_OK if written succesfully.                      *
  696. ******************************************************************************/
  697. static int EGifCompressOutput(GifFilePrivateType *Private, int Code)
  698. {
  699.     int retval = GIF_OK;
  700.  
  701.     if (Code == FLUSH_OUTPUT) {
  702.     while (Private -> CrntShiftState > 0) {
  703.         /* Get Rid of what is left in DWord, and flush it. */
  704.         if (EGifBufferedOutput(Private -> File, Private -> Buf,
  705.         Private -> CrntShiftDWord & 0xff) == GIF_ERROR)
  706.             retval = GIF_ERROR;
  707.         Private -> CrntShiftDWord >>= 8;
  708.         Private -> CrntShiftState -= 8;
  709.     }
  710.     Private -> CrntShiftState = 0;               /* For next time. */
  711.     if (EGifBufferedOutput(Private -> File, Private -> Buf,
  712.         FLUSH_OUTPUT) == GIF_ERROR)
  713.                 retval = GIF_ERROR;
  714.     }
  715.     else {
  716.     Private -> CrntShiftDWord |= ((long) Code) << Private -> CrntShiftState;
  717.     Private -> CrntShiftState += Private -> RunningBits;
  718.     while (Private -> CrntShiftState >= 8) {
  719.         /* Dump out full bytes: */
  720.         if (EGifBufferedOutput(Private -> File, Private -> Buf,
  721.         Private -> CrntShiftDWord & 0xff) == GIF_ERROR)
  722.             retval = GIF_ERROR;
  723.         Private -> CrntShiftDWord >>= 8;
  724.         Private -> CrntShiftState -= 8;
  725.     }
  726.     }
  727.  
  728.     /* If code cannt fit into RunningBits bits, must raise its size. Note */
  729.     /* however that codes above 4095 are used for special signaling.      */
  730.     if (Private -> RunningCode >= Private -> MaxCode1 && Code <= 4095) {
  731.     Private -> MaxCode1 = 1 << ++Private -> RunningBits;
  732.     }
  733.  
  734.     return retval;
  735. }
  736.  
  737. /******************************************************************************
  738. *   This routines buffers the given characters until 255 characters are ready *
  739. * to be output. If Code is equal to -1 the buffer is flushed (EOF).          *
  740. *   The buffer is Dumped with first byte as its size, as GIF format requires. *
  741. *   Returns GIF_OK if written succesfully.                      *
  742. ******************************************************************************/
  743. static int EGifBufferedOutput(FILE *File, GifByteType *Buf, int c)
  744. {
  745.     if (c == FLUSH_OUTPUT) {
  746.     /* Flush everything out. */
  747.     if (Buf[0] != 0 && fwrite(Buf, 1, Buf[0]+1, File) != Buf[0] + 1)
  748.     {
  749.         _GifError = E_GIF_ERR_WRITE_FAILED;
  750.         return GIF_ERROR;
  751.     }
  752.     /* Mark end of compressed data, by an empty block (see GIF doc): */
  753.     Buf[0] = 0;
  754.     if (fwrite(Buf, 1, 1, File) != 1)
  755.     {
  756.         _GifError = E_GIF_ERR_WRITE_FAILED;
  757.         return GIF_ERROR;
  758.     }
  759.     }
  760.     else {
  761.     if (Buf[0] == 255) {
  762.         /* Dump out this buffer - it is full: */
  763.         if (fwrite(Buf, 1, Buf[0] + 1, File) != Buf[0] + 1)
  764.         {
  765.         _GifError = E_GIF_ERR_WRITE_FAILED;
  766.         return GIF_ERROR;
  767.         }
  768.         Buf[0] = 0;
  769.     }
  770.     Buf[++Buf[0]] = c;
  771.     }
  772.  
  773.     return GIF_OK;
  774. }
  775.